library(tidyverse)
library(gridExtra)
library(grid)
library(readxl)
htmlwidgets는 자바스크립트를 R에 임베딩하는 프레임워크이며, htmlwidgets를 통해 만들어진 결과물들은 interactivity를 제외하면 다른 R 플롯과 동일하게 작동합니다. 수많은 R 패키지들이 htmlwidgets를 통해 개발되었고, htmlwidgets 갤러리를 방문하시면 그 목록들을 확인해볼 수 있습니다. 물론 이 글에서 이 패키지들을 전부 다룰 수는 없으며, 대표적인 몇 가지 패키지와 애드온만을 가지고 실습을 진행할 것입니다.
이번 장에서 활용할 데이터는 코에이의 시뮬레이션 게임 ’삼국지13’의 도시별 데이터입니다. 먼저 도시별 데이터를 읽어온 후, 필요한 컬럼들을 선택하고 인물에 따라 위, 촉, 오를 구분하였습니다. 위, 촉, 오에 속하지 않는 도시들은 걸러내고 비병역인구와 병역인구를 합쳐 인구 컬럼을 생성하였습니다. 최종적으로 만들어진 데이터는 다음과 같습니다.
# 데이터 읽기
data = read_excel("data/kingdoms.xlsx", sheet='도시')
# 전처리
data = data %>%
select(지방, 도시, 주, 주도, 군단, 태수, 자금, 군량, 비병역인구, 병역인구, 상업, 농업, 문화) %>% # 필요한 컬럼 선택
mutate(삼국 = case_when(군단 == "관우" ~ "촉",
군단 == "유비" ~ "촉",
군단 == "장로" ~ "촉",
군단 == "조조" ~ "위",
군단 == "장료" ~ "위",
군단 == "공손공" ~ "위",
군단 == "손권" ~ "오")) %>% # 군단에 따라 위, 촉, 오로 구분
filter(!is.na(삼국)) %>% # 위촉오에 속하지 않는 도시 걸러냄
mutate(인구 = 비병역인구 + 병역인구) # 인구 컬럼 생성
head(data)
## # A tibble: 6 x 15
## 지방 도시 주 주도 군단 태수 자금 군량 비병역인구 병역인구 상업
## <chr> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 하북 양평 유주 × 공손공~ 공손공~ 3000 30800 138200 15400 2320
## 2 하북 북평 유주 × 조조 조창 3600 30000 135200 15000 2340
## 3 하북 계 유주 ○ 조조 전예 4150 49000 220500 24500 2780
## 4 하북 남피 기주 × 조조 양습 3950 47600 214200 23800 2640
## 5 하북 중산 기주 × 조조 진림 3850 42400 190800 21200 2270
## 6 하북 거록 기주 × 조조 장패 4250 51200 228600 25600 2340
## # ... with 4 more variables: 농업 <dbl>, 문화 <dbl>, 삼국 <chr>, 인구 <dbl>
DT 패키지를 통해서 문서 안에 손쉽게 인터랙티브 테이블을 포함할 수 있습니다. DT::datatable()을 통해 생성한 결과가 head(data)로 출력한 결과보다 훨씬 알아보기 쉽습니다. DT 패키지를 통해 생성된 인터랙티브 테이블은 페이지 넘김, 정렬, 검색 등의 기능을 제공합니다. 따라서 문서의 독자는 표로부터 원하는 정보를 보다 쉽게 얻어갈 수 있습니다.
data %>% DT::datatable()
이번에는 인터랙티브 플롯을 다뤄볼 차례입니다. 많은 R 사용자들에게 익숙한 ggplot2 패키지에 plotly 패키지를 조합하여 간단한 인터랙티브 플롯들을 다뤄볼 것입니다.
library(plotly)
왼쪽 플로은 ggplot패키지를 이용해 그린 산점도를 인터랙티브 플롯으로 바꿔준 예제입니다. 도시별 데이터에서 산점도 객체를 생성한 후, 이 객체를 ggplotly 함수에 넣어줍니다. 이제 점 위에 커서를 가져다 대면 국가, 자금, 군량에 대한 툴팁이 표시됩니다. 플롯의 툴팁은 기본적으로 aes 에 전달된 모든 정보를 포함합니다.
오른쪽 플롯은 툴팁을 직접 수정해준 예제입니다. ggplot의 aes에 text 파라미터를 추가하고, 원하는 툴팁 내용을 문자열로 입력해주면 됩니다. 이번 예제에서는 인구 정보를 추가하였습니다. 마지막으로 ggplotly함수에 tooptip='text'를 넣어주면 끝입니다.
font = list(
family = "나눔스퀘어라운드 Regular",
size = 14,
color = "black")
p = data %>%
# x축에 자금, y축에 군량, 국가별로 마커 색과 모양 구분
ggplot(aes(x=자금, y=군량, color=삼국, shape=삼국)) +
geom_point() + # 산점도
theme_bw()
subtitle = list(
text = "1) 인터랙티브 플롯 예제",
font=font,
xref = "paper",
yref = "paper",
yanchor = "bottom",
xanchor = "center",
align = "left",
x = 0.5,
y = 1,
showarrow = FALSE
)
p1 = ggplotly(p) %>% hide_legend() %>% layout(annotations=subtitle) # 인터랙티브 플롯으로
p = data %>%
ggplot(aes(x=자금,
y=군량,
color=삼국,
shape=삼국,
# 툴팁 텍스트 수정
text=paste0("국가 :", 삼국, "\n",
"자금 :", 자금, "\n",
"군량 :", 군량, "\n",
"인구 :", 인구))) +
geom_point() +
theme_bw()
subtitle = list(
text = "2) 툴팁 수정 예제",
font=font,
xref = "paper",
yref = "paper",
yanchor = "bottom",
xanchor = "center",
align = "left",
x = 0.5,
y = 1,
showarrow = FALSE
)
# 툴팁에 text만 표시되도록 tooptip='text' 전달
p2 = ggplotly(p, tooltip='text') %>% layout(annotations=subtitle)
#
plotly::subplot(p1, p2, margin = 0.025, shareY=T, shareX=T) %>%
layout(autosize = F, width = 800, height = 400)
이번에는 하이라이트 기능을 통해서 원하는 데이터 포인트를 강조해보도록 하겠습니다. 데이터로부터 ggplot 객체를 생성하기 전에, highlight_key 함수를 통해서 하이라이트의 키가 될 변수를 설정해줍니다. 이후에는 똑같이 ggplotly 객체를 생성해주면 됩니다. 마지막으로 ggplotly 객체를 highlight 함수에 넣어서 하이라이트 플롯을 생성합니다. highlight 함수의 파라미터에 대한 더 구체적인 설명은 여기를 참고해주세요.
# 하이라이트 키가 될 변수를 지정해줍니다.
kingdoms_highlight = highlight_key(data, ~삼국)
# ggplot 객체를 생성합니다.
p = kingdoms_highlight %>%
ggplot(aes(x=자금,
y=군량,
color=삼국,
shape=삼국,
text=paste0("국가 :", 삼국, "\n",
"자금 :", 자금, "\n",
"군량 :", 군량, "\n",
"인구 :", 인구))) +
geom_point() +
theme_bw() +
ggtitle("3) 하이라이트를 적용한 인터랙티브 플롯 예제")
# ggplotly 객체를 생성하고 highlight_gg에 할당합니다.
highlight_gg = ggplotly(p, tooltip = "text")
# 하이라이트 플롯을 생성합니다.
highlight(highlight_gg,
# 클릭을 통해서 하이라이트가 활성화되도록 합니다.
on = "plotly_click",
# 선택된 키들을 표시합니다.
selectize = TRUE)
## Setting the `off` event (i.e., 'plotly_doubleclick') to match the `on` event (i.e., 'plotly_click'). You can change this default via the `highlight()` function.